<?php

namespace SinoPHP\BbdBoss;

use LogicException;
use InvalidArgumentException;
use ReflectionMethod;
use SinoPHP\BbdBoss\Defines\ApiCode;
use Upfor\UpforPHP\Controller;
use Upfor\UpforPHP\Http\Url;
use SinoPHP\BbdBoss\Library\AdminAuth;

/**
 * Abstract Controller
 */
abstract class AdminController extends Controller {

    /**
     * 是否登录
     *
     * @var false|integer
     */
    protected $isLogin;

    /**
     * 每页显示条数
     *
     * @var int
     */
    protected $limit = 15;

    /**
     * 当前登录的管理员用户信息(来自SESSION)
     *
     * @var array|null
     */
    protected $currentUserInfo;

    public function __construct() {
        parent::__construct();

        // 检验是否登录&白名单判断
        $this->isLogin = isAdminLogin();
        $this->currentUserInfo = getCurrentAdminUserInfo();
        $whiteList = config('loginWhiteList') ? : [];

        if (!in_array($this->controller, $whiteList) && !in_array($this->controller . '/' . $this->action, $whiteList)) {
            if (!$this->isLogin) {
                // 不同的METHOD展现形式不同
                if (request()->isGet()) {
                    redirect('/AdminUser/login');
                } else {
                    $this->error(101012);
                }
            } else {
                // if (!$this->checkUserPermission($this->isLogin)) {
                //     $this->error(101013);
                // }
            }
        }

        // 对于页面请求, 设置公共资源
        if (request()->isGet()) {
            // $this->initPageConfig();
        }
    }

    /**
     * 检查URL访问权限
     *
     * @param  integer $userId
     * @return boolean
     */
    protected function checkUserPermission($userId) {
        $userNodes = $this->currentUserInfo['nodes'];
        $auth = new AdminAuth();

        // 超级管理员拥有所有权限
        if ($auth->isSuper($userId)) {
            return true;
        }

        $allPermissions = $auth->getAllPermissions();
        $inAll = false; // 标记: 当前URL是否在权限列表中
        foreach ($allPermissions as $node) {
            if ($node['controller'] != $this->controller) {
                continue;
            }

            if ($node['action'] != $this->action) {
                continue;
            }

            // 解码Params为数组
            $node['params'] = $auth->decodeParams($node['params']);

            // 交集与权限参数本身完全一致
            $diffParams = array_intersect_assoc($node['params'], request()->get());
            if (array_diff_key($diffParams, $node['params'])) {
                continue;
            }

            // 完全匹配上, 标记为在权限列表中
            $inAll = true;

            // 用户的权限节点里有该权限
            if (in_array($node['node_id'], $userNodes)) {
                return true;
            }
        }

        // 如果该地址不在权限列表中, 则不限制权限
        if (!$inAll) {
            return true;
        }

        // 在权限列表中, 却不在用户的权限内, 则表明无权限
        return false;
    }

    /**
     * 初始化页面配置
     */
    protected function initPageConfig() {
        // JS公共资源文件
        $this->setJsResource(array(
            'global/jquery.min.js',
            'global/bootstrap.min.js',
            'global/jquery.bdb.min.js',
            'global/main.min.js',
        ));

        // CSS公共资源文件
        $this->setCssResource(array(
            'global/bootstrap.min.css',
            'global/main.css',
        ));

        // 查询用户所拥有的菜单列表
        if ($this->isLogin) {
            $this->matchNode();
        }
    }

    /**
     * 匹配当前URL权限&菜单
     */
    private function matchNode() {
        $adminUserInfo = getCurrentAdminUserInfo();
        $this->assign('adminUserInfo', $adminUserInfo);

        // 匹配当前URL
        $auth = new AdminAuth();
        $matchedNodes = $auth->getMatchedNodes([
            'controller' => $this->controller,
            'action' => $this->action,
        ]);

        foreach ($matchedNodes as $node) {
            $node['params'] = $auth->decodeParams($node['params']);
            $diffParams = array_intersect_assoc($node['params'], request()->get());
            if (!array_diff_key($diffParams, $node['params'])) {
                $currentNode = $node;
                $this->assign('currentNode', $currentNode);
            }
        }

        if (!empty($currentNode)) {
            foreach ($adminUserInfo['menus'] as $topMenu) {
                if ($topMenu['node_id'] == $currentNode['pid']) {
                    $this->assign('topMenu', $topMenu);
                    $this->assign('secondMenu', $currentNode);
                    break;
                }

                foreach ($topMenu['sub'] as $secondMenu) {
                    if ($secondMenu['node_id'] == $currentNode['pid']) {
                        $this->assign('topMenu', $topMenu);
                        $this->assign('secondMenu', $secondMenu);
                        break 2;
                    }
                }
            }
        }
    }

    /**
     * 记录管理员操作日志
     *
     * @param string       $brief
     * @param array|string $detail
     */
    public function addActionLog($brief, $detail = null) {
        // 获取当前操作Title
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        $backtrace = $backtrace[1];
        $refObj = new ReflectionMethod($backtrace['class'], $backtrace['function']);
        $pattern = '#^(?!\@)(.+)#u';
        $commentLines = explode("\n", $refObj->getDocComment());
        array_shift($commentLines);
        array_pop($commentLines);
        foreach ($commentLines as $line) {
            $line = trim($line);
            $line = ltrim($line, '*');
            $line = trim($line);

            if (preg_match($pattern, $line, $match)) {
                $methodTitle = $match[0];
                break;
            }
        }

        if (empty($methodTitle)) {
            throw new InvalidArgumentException('Method miss title comment ' . $backtrace['class'] . '::' . $backtrace['function']);
        }

        // 处理日志数据
        if (empty($detail)) {
            $detail = [
                'input' => request()->post(),
            ];
        }
        if (!is_scalar($detail)) {
            $detail = json_encode($detail, JSON_UNESCAPED_UNICODE);
        }

        // 构建日志信息
        $adminUserInfo = getCurrentAdminUserInfo();
        $logData = [
            'admin_user_id' => $adminUserInfo['admin_user_id'],
            'username' => $adminUserInfo['real_name'],
            'action' => $methodTitle,
            'brief' => $brief,
            'ip' => request()->getRemoteIp(),
            'create_time' => time(),
            'detail' => $detail,
        ];

        // 存入数据库
        model('AdminOperateLog')->insert($logData);
    }

    /**
     * 失败返回
     *
     * @param integer $code
     * @param string  $msg
     */
    public function error($code, $msg = null) {
        static $apiCodeStatus = array();
        if (!$apiCodeStatus) {
            $apiCodeStatus = ApiCode::$statusCode;
        }

        if (!isset($apiCodeStatus[$code])) {
            throw new LogicException('Unknown api error code');
        }

        if (!$msg) {
            $msg = $apiCodeStatus[$code];
        }
        $this->response([], $code, $msg);
    }

}
